/*
 * 这个文件修改为：
 *     - 读取系统环境变量的操作放在 util 里当成工具才行
 *     - 数据库连接设置为 连接池 并 支持心跳包
 *     - 对外暴露:
 *         1. sqlExec                普通执行sql语句并关闭连接
 *         2. sqlExecInTransaction   在事务环境下执行sql语句不关闭连接
 *         3. startTransaction       开始事务
 *         4. commitTransaction      提交事务
 *         5. rollbackTransaction    回滚事务
 */

const config = require('../util/server_config');
const mysql = require('mysql');

// 获取环境变量的值
const { host, port, user, pswd, database } = config.mysql;

// 输出日志
console.log('\n正在连接数据库。。。请稍等。。。');

let db;

// 心跳包机制：定期检查连接状态
function checkConnection() {
    db.getConnection((err, connection) => {
        if (err) {
            console.error('无法获取数据库连接:', err);
            return;
        }
        // 使用 ping 方法检查连接状态
        connection.ping((err) => {
            // 释放连接回连接池
            connection.release();
            if (err) {
                console.error('数据库连接已断开:', err);
            } else {
                console.log('数据库连接正常');
            }
        });
    });
}

function initMysql57() {
    // 限制 mysql 只初始化一次
    if (db) return ;
    return new Promise((resolve, reject) => {
        // 输出连接信息
        console.log('正在连接 mysql57 数据库 ...', host, port);
        // 连接数据库
        db = mysql.createPool({
            host: host,
            port: port,
            user: user,
            password: pswd,
            database: database,
            idleTimeoutMinutes: 60,
            acquireTimeout: 60000,
            waitForConnections: true,
        });
        // 检测数据库是否连接成功
        db.getConnection((err, connection) => {
            if (err) {
                console.error(`mysql数据库连接失败 ! ! ! !`);
                console.error(` -> host: ${host}`);
                console.error(` -> port: ${port}`);
                console.error(` -> user: ${user}`);
                console.error(` -> password: ${pswd}`);
                console.error(` -> database: ${database}`);
                reject("mysql数据库连接失败 ! ! ! !");
                process.exit(1);
            } else {
                console.log('mysql 数据库连接成功！  数据库进程id为: ' + connection.threadId);
                // 释放连接
                connection.release();
                // 每 3 分钟检查一次连接状态
                setInterval(checkConnection, 3 * 60 * 1000);
                // 返回连接成功的状态
                resolve("mysql57 连接成功 ! ! ! !");
            }
        });
    });
}


// 单步执行sql的方法
function sqlExec(sql, data) {
    return new Promise((resolve, reject) => {
        db.getConnection((err, connection) => {
            if (err) {
                // 连不上数据库
                connection.release();
                reject(err);
                return ;
            }
            connection.query(sql, data, function (err, result) {
                if (err) {
                    // 连上数据库之后，执行sql时发生错误
                    connection.release();
                    reject(err);
                    return ;
                }
                connection.release();
                resolve(result);
            });
        });
    });
}

/*
 * 事务环境下的单步执行的方法
 */
function sqlExecInTransaction(connection, sql, data) {
    return new Promise((resolve, reject) => {
        connection.query(sql, data, function (err, result) {
            if (err) {
                // 连上数据库之后，执行sql时发生错误
                connection.release();
                reject(err);
                return ;
            }
            resolve(result);
        });
    });
}

/*
 * 开启事务的方法
 * 返回一个 Promise 对象，用于在事务开始后返回连接
 */
function startTransaction() {
    return new Promise((resolve, reject) => {
        db.getConnection((err, connection) => {
            if (err) {
                // 连不上数据库
                reject(err);
                return;
            }
            connection.beginTransaction((err) => {
                if (err) {
                    // 开启事务失败
                    connection.release();
                    reject(err);
                    return;
                }
                // 事务开启成功，返回连接以便后续操作
                resolve(connection);
            });
        });
    });
}

/*
 * 提交事务的方法
 */
function commitTransaction(connection) {
    return new Promise((resolve, reject) => {
        connection.commit((err) => {
            if (err) {
                // 提交事务失败
                connection.rollback(() => {
                    connection.release();
                    reject(err);
                });
                return;
            }
            // 提交事务成功，释放连接
            connection.release();
            resolve();
        })
    })
}

/*
 * 回滚事务的方法
 */
function rollbackTransaction(connection) {
    return new Promise((resolve, reject) => {
        connection.rollback((err) => {
            if (err) {
                // 回滚事务失败
                connection.release();
                reject(err);
                return;
            }
            // 回滚事务成功，释放连接
            connection.release();
            resolve();
        });
    });
}

module.exports = {
    initMysql57,
    db,
    sqlExec,
    sqlExecInTransaction,
    startTransaction,
    commitTransaction,
    rollbackTransaction
};
